package org.thingsboard.server.service.transport;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.thingsboard.server.config.SpringUtils;
import org.thingsboard.server.config.factory.AsyncFactory;
import org.thingsboard.server.config.factory.AsyncManager;
import org.thingsboard.server.controller.swagger.DeviceServiceController;
import org.thingsboard.server.dao.jpa.*;
import org.thingsboard.server.dao.jpa.imp.*;
import org.thingsboard.server.utils.HttpUtil;
import org.thingsboard.server.utils.msg.MqttReqMsg;

import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class ProcessServiceImp implements ProcessService {

    @Autowired
    private DeviceCompanyRepository deviceCompanyRepository;


    @Autowired
    private SysParamRepository sysParamRepository;

    @Autowired
    private GatewayRepository gatewayRepository;

    @Autowired
    private DeviceModelRepository deviceModelRepository;

    @Autowired
    private TDeviceRepository TDeviceRepository;

    @Autowired
    private DevicePropertyRepository devicePropertyRepository;

    private final Gson gson = new Gson();
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private AppRepository appRepository;

    @Autowired
    private ConcurrentHashMap<String, TApp> appManagement;

    @Autowired
    private DeviceEventRepository deviceEventRepository;

    @Autowired
    private DeviceServiceRepository deviceServiceRepository;


    @Override
    public Map getMap(String gateCode) {
        Map map = new HashMap();
        Iterable<TSysParam> list = sysParamRepository.findAll();
        List<Map> systemArg = new ArrayList<Map>();
        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
            Map data = new HashMap();
            TSysParam sysParam = (TSysParam) iter.next();
            data.put("key", sysParam.getParamEnName());
            data.put("type", "String");
            data.put("value", sysParam.getParamValue());
            systemArg.add(data);
        }
        JsonArray array = new JsonArray();
        TGateway gateway = gatewayRepository.findByGatewayCode(gateCode);
        if (null != gateway) {
            if (!gateway.getGatewayArg().isEmpty()) {
                array = gson.fromJson(gateway.getGatewayArg(), JsonObject.class).get("configArg").getAsJsonArray();
            }
        }
        List<TDeviceModel> modelList = deviceModelRepository.findModels(gateCode);
        List<Map> modeMaps = new ArrayList<>();
        for (TDeviceModel model : modelList) {
            Map data = (Map) gson.fromJson(gson.toJson(model), Map.class);
            JsonObject modelArg = gson.fromJson(model.getModelArg(), JsonObject.class);
            JsonArray propertyList = modelArg.get("propertyList").getAsJsonArray();
            propertyList.forEach(property -> {
                TDeviceProperty tDeviceProperty = devicePropertyRepository.findByDpropertyCode(property.getAsJsonObject().get("propertyCode").getAsString());
                if (null != tDeviceProperty&&!StringUtils.isEmpty(tDeviceProperty.getDpropertyArg())) {
                    property.getAsJsonObject().add("configArg", gson.fromJson(tDeviceProperty.getDpropertyArg(), JsonObject.class).get("configArg").getAsJsonArray());
                }else{
                    property.getAsJsonObject().add("configArg",new JsonArray());
                }
            });
            modelArg.add("propertyList", propertyList);
            JsonArray eventList = modelArg.get("eventList").getAsJsonArray();
            eventList.forEach(event -> {
                TDeviceEvent tDeviceEvent = deviceEventRepository.findByDeventCode(event.getAsJsonObject().get("eventCode").getAsString());
                if (null != tDeviceEvent&&!StringUtils.isEmpty(tDeviceEvent.getDeventArg())) {
                    event.getAsJsonObject().add("configArg", gson.fromJson(tDeviceEvent.getDeventArg(), JsonObject.class).get("configArg").getAsJsonArray());
                    event.getAsJsonObject().addProperty("eventType",tDeviceEvent.getDeventType());
                }else{
                    event.getAsJsonObject().add("configArg",new JsonArray());
                }
            });
            modelArg.add("eventList", eventList);

            JsonArray serviceList = modelArg.get("serviceList").getAsJsonArray();
            serviceList.forEach(service -> {
                TDeviceService tDeviceService = deviceServiceRepository.findByDserviceCode(service.getAsJsonObject().get("serviceCode").getAsString());
                if (null != tDeviceService&&!StringUtils.isEmpty(tDeviceService.getDserviceArg())) {
                    service.getAsJsonObject().add("configArg", gson.fromJson(tDeviceService.getDserviceArg(), JsonObject.class).get("configArg").getAsJsonArray());
                }else{
                    service.getAsJsonObject().add("configArg",new JsonArray());
                }
            });
            modelArg.add("serviceList", serviceList);
            data.put("modelArg", modelArg);
            modeMaps.add(data);
        }
        List<TDevice> deviceList = TDeviceRepository.findTDevicesByGatewayCode(gateCode);
        List<Map> deviceMaps = new ArrayList<>();
        for (TDevice model : deviceList) {
            Map data = (Map) gson.fromJson(gson.toJson(model), Map.class);
            data.put("configArg", gson.fromJson(model.getDeviceArg(), JsonObject.class).get("configArg").getAsJsonArray());
            deviceMaps.add(data);
        }
        List<Map> companyMaps = new ArrayList<>();
        Iterable<TDeviceCompany> companyList = deviceCompanyRepository.findAll();
        for (Iterator iter = companyList.iterator(); iter.hasNext(); ) {
            TDeviceCompany deviceCompany = (TDeviceCompany) iter.next();
            Map data = (Map) gson.fromJson(gson.toJson(deviceCompany), Map.class);
            if (null != deviceCompany.getCompanyArg() && !StringUtils.isEmpty(deviceCompany.getCompanyArg())) {
                data.put("configArg", gson.fromJson(deviceCompany.getCompanyArg(), JsonObject.class).get("configArg").getAsJsonArray());
            }
            companyMaps.add(data);
        }
        map.put("companyList", companyMaps);
        map.put("systemArg", systemArg);
        map.put("modelList", modeMaps);
        map.put("deviceList", deviceMaps);
        map.put("agentArg", array);
        return map;
    }

    @Override
    public void doDeviceProcess(MqttReqMsg msg, JsonObject json) {
        if (null != json.getAsJsonObject().getAsJsonObject("requestBody").get("eventCode") && null != json.getAsJsonObject().getAsJsonObject("requestBody").get("eventArg")) {
            TApp app = new TApp();
            app = appManagement.get(json.getAsJsonObject().getAsJsonObject("requestBody").get("deviceCode").getAsString());
            if (null == app) {
                app = appRepository.getApp(json.getAsJsonObject().getAsJsonObject("requestBody").get("deviceCode").getAsString());
                if (null != app) {
                    appManagement.put(json.getAsJsonObject().getAsJsonObject("requestBody").get("deviceCode").getAsString(), app);
                }
            }
            if (null != app && !StringUtils.isEmpty(app.getAppArg())) {
                String url = "";
                JsonArray args = gson.fromJson(app.getAppArg(), JsonObject.class).get("configArg").getAsJsonArray();
                for (JsonElement arg : args) {
                    if ("url".equals(arg.getAsJsonObject().get("key").getAsString())) {
                        url = arg.getAsJsonObject().get("value").getAsString();
                    }
                }
                if (!StringUtils.isEmpty(url)) {
                    System.out.println("平台收到的报文: "+json.getAsJsonObject().toString());
                    json.getAsJsonObject().getAsJsonObject("requestHead").addProperty("systemCode", "SYSTEM-IOT");
                    json.getAsJsonObject().getAsJsonObject("requestBody").addProperty("timestamp", json.getAsJsonObject().getAsJsonObject("requestHead").get("timestamp").getAsLong());
                    System.out.println("平台组装后的报文: "+json.getAsJsonObject().toString());
                    HttpUtil.doPost(url, json);
                }
            }
            AsyncManager.me().execute(AsyncFactory.recordEvent(msg, json, app, redisTemplate));
        }
    }

    @Override
    public void doDeviceAttr(MqttReqMsg msg, JsonObject jsonObject) {
        final Gson gson = new Gson();
        String deviceCode = jsonObject.getAsJsonObject("requestBody").get("deviceCode").getAsString();
        JsonArray jsonArray = jsonObject.getAsJsonObject("requestBody").get("propertyList").getAsJsonArray();
        for (JsonElement element : jsonArray) {
            TDeviceProperty tDeviceProperty = SpringUtils.getBean(DevicePropertyRepository.class).findByDpropertyCode(element.getAsJsonObject().get("key").getAsString());
            ArrayList strs = new ArrayList();
            String stringArg = tDeviceProperty.getDpropertyArg();
            if (!stringArg.isEmpty()) {
                JsonArray values = gson.fromJson(stringArg, JsonObject.class).get("configArg").getAsJsonArray().get(0).getAsJsonObject().get("value").getAsJsonArray();
                strs = gson.fromJson(values, ArrayList.class);
            }
            if (strs.contains("ram")) {
                ConcurrentHashMap<String,String> deviceAttrManagement = SpringUtils.getBean("deviceAttrManagement");
                deviceAttrManagement.put(deviceCode + element.getAsJsonObject().get("key").getAsString(), element.getAsJsonObject().toString());
            }
            if (strs.contains("redis")) {
                redisTemplate.opsForValue().set(deviceCode + element.getAsJsonObject().get("key").getAsString(), element.getAsJsonObject().toString());
            }
            if (strs.contains("db")) {
                TData tData = new TData();
                tData.setDataId(UUID.randomUUID().toString().replace("-", ""));
                tData.setDataTime(new Date(msg.getRequestHead().getTimestamp()));
                tData.setDeviceCode(deviceCode);
                tData.setDataVal(element.getAsJsonObject().get("key").getAsString());
                tData.setDpropertyCode(element.getAsJsonObject().get("value").getAsString());
                SpringUtils.getBean(DataRepository.class).save(tData);
            }
        }
//        AsyncManager.me().execute(AsyncFactory.recordAttr(msg, jsonObject, redisTemplate));
    }

    public static void main(String[] args) {
        Date date=new Date(1599016349000l);
        DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        System.out.println(df.format(date));
        Gson gson =new Gson();
        JsonObject obj= gson.fromJson("{\n" +
                "\t\"requestBody\": {\n" +
                "\t\t\"deviceCode\": \"device-dky-8101_rps\",\n" +
                "\t\t\"eventArg\": [{\n" +
                "\t\t\t\"key\": \"alarmLevel\",\n" +
                "\t\t\t\"type\": \"string\",\n" +
                "\t\t\t\"value\": \"normal\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"key\": \"alarmVal\",\n" +
                "\t\t\t\"type\": \"string\",\n" +
                "\t\t\t\"value\": \"28\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"key\": \"alarmDes\",\n" +
                "\t\t\t\"type\": \"string\",\n" +
                "\t\t\t\"value\": \"录播系统发生异常\"\n" +
                "\t\t}],\n" +
                "\t\t\"eventCode\": \"event-alarm\",\n" +
                "\t\t\"eventType\": \"etype-alarm\"\n" +
                "\t},\n" +
                "\t\"requestHead\": {\n" +
                "\t\t\"agentId\": \"iot-agent-java-001\",\n" +
                "\t\t\"gatewayId\": \"iot-gateway-001\",\n" +
                "\t\t\"msgId\": \"aedd8e379cf94386b80f1bcf4431be6c\",\n" +
                "\t\t\"msgType\": \"mtype-event-report\",\n" +
                "\t\t\"msgTypeE\": \"EVENT_REPORT\",\n" +
                "\t\t\"timestamp\": 1599016349000\n" +
                "\t}\n" +
                "}",JsonObject.class);
        MqttReqMsg msg = gson.fromJson(obj, MqttReqMsg.class);
        System.out.println("-------"+msg.getRequestHead().getTimestamp());
        System.out.println(System.currentTimeMillis());


    }
}
